// materialSystem.js - 材质系统和光照管理器
import { reactive, ref, computed } from 'vue'

/**
 * 材质系统 - 管理PBR材质和纹理
 */
export class MaterialSystem {
    constructor(gl) {
        this.gl = gl
        this.materials = new Map()
        this.textures = new Map()
        this.defaultMaterial = this.createDefaultMaterial()
    }

    /**
     * 创建默认材质
     */
    createDefaultMaterial() {
        return {
            name: 'Default',
            type: 'PBR',
            baseColor: [0.8, 0.8, 0.8, 1.0],
            metallic: 0.0,
            roughness: 0.5,
            emissive: [0.0, 0.0, 0.0],
            normalScale: 1.0,
            occlusionStrength: 1.0,

            // 纹理贴图
            baseColorTexture: null,
            metallicRoughnessTexture: null,
            normalTexture: null,
            emissiveTexture: null,
            occlusionTexture: null,

            // 渲染状态
            doubleSided: false,
            alphaMode: 'OPAQUE',
            alphaCutoff: 0.5,

            // 扩展属性
            envMapIntensity: 1.0,
            clearcoat: 0.0,
            clearcoatRoughness: 0.0,
            sheen: [0.0, 0.0, 0.0],
            transmission: 0.0
        }
    }

    /**
     * 创建材质
     */
    createMaterial(name, properties = {}) {
        const material = {
            ...this.createDefaultMaterial(),
            name,
            ...properties
        }

        this.materials.set(name, material)
        return material
    }

    /**
     * 加载纹理
     */
    async loadTexture(url, options = {}) {
        if (this.textures.has(url)) {
            return this.textures.get(url)
        }

        const gl = this.gl
        const texture = gl.createTexture()

        // 创建1x1像素的占位纹理
        gl.bindTexture(gl.TEXTURE_2D, texture)
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]))

        // 异步加载实际纹理
        const image = new Image()
        image.crossOrigin = options.crossOrigin || 'anonymous'

        return new Promise((resolve, reject) => {
            image.onload = () => {
                gl.bindTexture(gl.TEXTURE_2D, texture)
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)

                // 设置纹理参数
                const wrapS = options.wrapS || gl.REPEAT
                const wrapT = options.wrapT || gl.REPEAT
                const minFilter = options.minFilter || gl.LINEAR_MIPMAP_LINEAR
                const magFilter = options.magFilter || gl.LINEAR

                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS)
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT)
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter)
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter)

                // 生成Mipmap
                if (this.isPowerOf2(image.width) && this.isPowerOf2(image.height)) {
                    gl.generateMipmap(gl.TEXTURE_2D)
                }

                const textureInfo = {
                    texture,
                    width: image.width,
                    height: image.height,
                    url
                }

                this.textures.set(url, textureInfo)
                resolve(textureInfo)
            }

            image.onerror = () => {
                reject(new Error(`纹理加载失败: ${url}`))
            }

            image.src = url
        })
    }

    /**
     * 创建程序化纹理
     */
    createProceduralTexture(name, generator, width = 256, height = 256) {
        const gl = this.gl
        const texture = gl.createTexture()
        const data = new Uint8Array(width * height * 4)

        // 生成纹理数据
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const index = (y * width + x) * 4
                const u = x / width
                const v = y / height
                const color = generator(u, v, x, y)

                data[index] = Math.floor(color[0] * 255)     // R
                data[index + 1] = Math.floor(color[1] * 255) // G
                data[index + 2] = Math.floor(color[2] * 255) // B
                data[index + 3] = Math.floor((color[3] || 1) * 255) // A
            }
        }

        gl.bindTexture(gl.TEXTURE_2D, texture)
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

        const textureInfo = {
            texture,
            width,
            height,
            name
        }

        this.textures.set(name, textureInfo)
        return textureInfo
    }

    /**
     * 检查是否为2的幂
     */
    isPowerOf2(value) {
        return (value & (value - 1)) === 0
    }

    /**
     * 获取材质
     */
    getMaterial(name) {
        return this.materials.get(name) || this.defaultMaterial
    }

    /**
     * 获取纹理
     */
    getTexture(name) {
        return this.textures.get(name)
    }

    /**
     * 清理资源
     */
    dispose() {
        const gl = this.gl

        // 删除纹理
        this.textures.forEach(textureInfo => {
            gl.deleteTexture(textureInfo.texture)
        })

        this.textures.clear()
        this.materials.clear()
    }
}

/**
 * 光照管理器 - 管理场景光照
 */
export class LightingManager {
    constructor() {
        this.lights = reactive(new Map())
        this.shadowMaps = new Map()
        this.config = reactive({
            enableShadows: true,
            shadowMapSize: 1024,
            shadowBias: 0.005,
            shadowRadius: 3.0,
            maxLights: 8
        })
    }

    /**
     * 添加环境光
     */
    addAmbientLight(name, properties) {
        const light = {
            type: 'ambient',
            name,
            color: properties.color || [1.0, 1.0, 1.0],
            intensity: properties.intensity || 0.1,
            ...properties
        }

        this.lights.set(name, light)
        return light
    }

    /**
     * 添加方向光
     */
    addDirectionalLight(name, properties) {
        const light = {
            type: 'directional',
            name,
            color: properties.color || [1.0, 1.0, 1.0],
            intensity: properties.intensity || 1.0,
            direction: properties.direction || [0, -1, 0],
            castShadow: properties.castShadow || false,
            shadowCamera: {
                left: -10,
                right: 10,
                top: 10,
                bottom: -10,
                near: 1,
                far: 50
            },
            ...properties
        }

        this.lights.set(name, light)
        return light
    }

    /**
     * 添加点光源
     */
    addPointLight(name, properties) {
        const light = {
            type: 'point',
            name,
            color: properties.color || [1.0, 1.0, 1.0],
            intensity: properties.intensity || 1.0,
            position: properties.position || [0, 0, 0],
            distance: properties.distance || 0, // 0 = 无限距离
            decay: properties.decay || 2, // 物理正确的平方衰减
            castShadow: properties.castShadow || false,
            ...properties
        }

        this.lights.set(name, light)
        return light
    }

    /**
     * 添加聚光灯
     */
    addSpotLight(name, properties) {
        const light = {
            type: 'spot',
            name,
            color: properties.color || [1.0, 1.0, 1.0],
            intensity: properties.intensity || 1.0,
            position: properties.position || [0, 0, 0],
            direction: properties.direction || [0, -1, 0],
            distance: properties.distance || 0,
            decay: properties.decay || 2,
            angle: properties.angle || Math.PI / 6, // 锥角
            penumbra: properties.penumbra || 0, // 半影
            castShadow: properties.castShadow || false,
            ...properties
        }

        this.lights.set(name, light)
        return light
    }

    /**
     * 添加区域光
     */
    addAreaLight(name, properties) {
        const light = {
            type: 'area',
            name,
            color: properties.color || [1.0, 1.0, 1.0],
            intensity: properties.intensity || 1.0,
            position: properties.position || [0, 0, 0],
            width: properties.width || 1,
            height: properties.height || 1,
            ...properties
        }

        this.lights.set(name, light)
        return light
    }

    /**
     * 更新光源属性
     */
    updateLight(name, properties) {
        const light = this.lights.get(name)
        if (light) {
            Object.assign(light, properties)
        }
    }

    /**
     * 移除光源
     */
    removeLight(name) {
        this.lights.delete(name)

        // 清理阴影贴图
        if (this.shadowMaps.has(name)) {
            this.shadowMaps.delete(name)
        }
    }

    /**
     * 获取光源数据（用于着色器）
     */
    getLightData() {
        const lightData = {
            ambient: { color: [0, 0, 0], intensity: 0 },
            directional: [],
            point: [],
            spot: [],
            area: []
        }

        this.lights.forEach(light => {
            switch (light.type) {
                case 'ambient':
                    lightData.ambient = {
                        color: light.color,
                        intensity: light.intensity
                    }
                    break
                case 'directional':
                    lightData.directional.push(light)
                    break
                case 'point':
                    lightData.point.push(light)
                    break
                case 'spot':
                    lightData.spot.push(light)
                    break
                case 'area':
                    lightData.area.push(light)
                    break
            }
        })

        return lightData
    }

    /**
     * 创建阴影贴图
     */
    createShadowMap(gl, light) {
        if (!this.config.enableShadows || !light.castShadow) return null

        const shadowMap = {
            framebuffer: gl.createFramebuffer(),
            texture: gl.createTexture(),
            size: this.config.shadowMapSize
        }

        // 创建深度纹理
        gl.bindTexture(gl.TEXTURE_2D, shadowMap.texture)
        gl.texImage2D(
            gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT24,
            shadowMap.size, shadowMap.size, 0,
            gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null
        )

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

        // 创建帧缓冲区
        gl.bindFramebuffer(gl.FRAMEBUFFER, shadowMap.framebuffer)
        gl.framebufferTexture2D(
            gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,
            gl.TEXTURE_2D, shadowMap.texture, 0
        )

        // 不需要颜色缓冲区
        gl.drawBuffers([gl.NONE])
        gl.readBuffer(gl.NONE)

        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
            console.error('阴影贴图帧缓冲区创建失败')
            return null
        }

        gl.bindFramebuffer(gl.FRAMEBUFFER, null)

        this.shadowMaps.set(light.name, shadowMap)
        return shadowMap
    }

    /**
     * 计算光照衰减
     */
    calculateAttenuation(light, distance) {
        if (light.distance === 0) return 1.0

        const attenuation = Math.pow(Math.max(1.0 - distance / light.distance, 0.0), light.decay)
        return attenuation
    }

    /**
     * 清理资源
     */
    dispose(gl) {
        // 清理阴影贴图
        this.shadowMaps.forEach(shadowMap => {
            gl.deleteTexture(shadowMap.texture)
            gl.deleteFramebuffer(shadowMap.framebuffer)
        })

        this.shadowMaps.clear()
        this.lights.clear()
    }
}

/**
 * 环境贴图管理器
 */
export class EnvironmentManager {
    constructor(gl) {
        this.gl = gl
        this.envMaps = new Map()
        this.currentEnvMap = null
    }

    /**
     * 创建立方体贴图
     */
    async createCubeMap(name, urls) {
        const gl = this.gl
        const texture = gl.createTexture()
        gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture)

        const faces = [
            { target: gl.TEXTURE_CUBE_MAP_POSITIVE_X, url: urls.px },
            { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X, url: urls.nx },
            { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y, url: urls.py },
            { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, url: urls.ny },
            { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z, url: urls.pz },
            { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, url: urls.nz }
        ]

        const loadPromises = faces.map(face => {
            return new Promise((resolve, reject) => {
                const image = new Image()
                image.crossOrigin = 'anonymous'
                image.onload = () => {
                    gl.texImage2D(face.target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)
                    resolve()
                }
                image.onerror = reject
                image.src = face.url
            })
        })

        await Promise.all(loadPromises)

        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE)

        const envMap = { texture, name, type: 'cubemap' }
        this.envMaps.set(name, envMap)
        return envMap
    }

    /**
     * 创建HDR环境贴图
     */
    async createHDREnvironment(name, url) {
        // HDR加载需要特殊处理，这里提供接口
        const gl = this.gl
        const texture = gl.createTexture()

        // 实际实现需要HDR加载器
        const envMap = { texture, name, type: 'hdr' }
        this.envMaps.set(name, envMap)
        return envMap
    }

    /**
     * 设置当前环境贴图
     */
    setCurrentEnvironment(name) {
        this.currentEnvMap = this.envMaps.get(name) || null
    }

    /**
     * 获取当前环境贴图
     */
    getCurrentEnvironment() {
        return this.currentEnvMap
    }

    /**
     * 清理资源
     */
    dispose() {
        const gl = this.gl
        this.envMaps.forEach(envMap => {
            gl.deleteTexture(envMap.texture)
        })
        this.envMaps.clear()
    }
}

/**
 * 预设材质库
 */
export const MaterialPresets = {
    // 金属材质
    metal: {
        baseColor: [0.7, 0.7, 0.7, 1.0],
        metallic: 1.0,
        roughness: 0.1
    },

    // 塑料材质
    plastic: {
        baseColor: [0.8, 0.2, 0.2, 1.0],
        metallic: 0.0,
        roughness: 0.7
    },

    // 木材材质
    wood: {
        baseColor: [0.6, 0.4, 0.2, 1.0],
        metallic: 0.0,
        roughness: 0.8
    },

    // 玻璃材质
    glass: {
        baseColor: [0.95, 0.95, 0.95, 0.1],
        metallic: 0.0,
        roughness: 0.0,
        transmission: 0.9,
        alphaMode: 'BLEND'
    },

    // 橡胶材质
    rubber: {
        baseColor: [0.1, 0.1, 0.1, 1.0],
        metallic: 0.0,
        roughness: 1.0
    },

    // 陶瓷材质
    ceramic: {
        baseColor: [0.9, 0.9, 0.8, 1.0],
        metallic: 0.0,
        roughness: 0.3
    },

    // 发光材质
    emissive: {
        baseColor: [1.0, 1.0, 1.0, 1.0],
        metallic: 0.0,
        roughness: 1.0,
        emissive: [2.0, 2.0, 2.0]
    }
}

/**
 * 程序化纹理生成器
 */
export const ProceduralTextures = {
    // 棋盘纹理
    checkerboard: (u, v) => {
        const checker = (Math.floor(u * 8) + Math.floor(v * 8)) % 2
        return checker ? [1, 1, 1, 1] : [0, 0, 0, 1]
    },

    // 噪声纹理
    noise: (u, v) => {
        const noise = Math.random()
        return [noise, noise, noise, 1]
    },

    // 渐变纹理
    gradient: (u, v) => {
        return [u, v, 0.5, 1]
    },

    // 条纹纹理
    stripes: (u, v) => {
        const stripe = Math.sin(u * Math.PI * 16) * 0.5 + 0.5
        return [stripe, stripe, stripe, 1]
    },

    // 圆形纹理
    circle: (u, v) => {
        const dx = u - 0.5
        const dy = v - 0.5
        const distance = Math.sqrt(dx * dx + dy * dy)
        const alpha = distance < 0.4 ? 1 : 0
        return [1, 1, 1, alpha]
    },

    // 法线贴图（凹凸）
    normalMap: (u, v) => {
        const height = Math.sin(u * Math.PI * 8) * Math.sin(v * Math.PI * 8) * 0.1
        // 简化的法线计算
        const normal = [0.5, 0.5, 1.0, 1.0]
        return normal
    }
}